package sql;

import java.util.*;

import parse.*;
import Const.*;
import ExecuteEngine.*;
import RecordManagement.*;
import SystemManagement.*;

public class User_Manager {
	Map<Integer, SM_Manager> openMap = new HashMap<Integer, SM_Manager>();
	SM_Manager user_manager;
	
	public User_Manager(){
		 user_manager = new SM_Manager();
		 if(user_manager.OpenDb("userInfo") != RC.rc.SUCCESS){
			 user_manager.CreateDB("userInfo");
			 
			 RM_FileHandle fileHandle = null;
			 RM_Manager rm = user_manager.rm;
	  		 try{
				 fileHandle = rm.CreateFile("userInfo.db", Constant.MAXNAME*3+Constant.INTSIZE);	
				 fileHandle.ForceAllPages();
				 rm.CloseFile(fileHandle);
			 }
			 catch(java.io.IOException e){
			 	
			 }
			 
			 user_manager.OpenDb("userInfo");
		 }
	}
	
	public int login(String name, String password){
		SM_Manager sm = null;
		
		RM_FileHandle filehandle = user_manager.OpenFile("userInfo");
		ScanType st = new ScanType(ScanType.TYPE_STRING, 
                Constant.MAXNAME, 0, ScanType.OP_NO,
                null, ScanType.PIN_NORMAL);

		RM_FileScan fileScan = new RM_FileScan(filehandle,st);
		RM_Record record;
		StringBuffer u = new StringBuffer(name);
		u.setLength(Constant.MAXNAME);
		StringBuffer p = new StringBuffer(password);
		p.setLength(Constant.MAXNAME);
		
		int ID = -1;
		String dir = null;
		for(int i=0; (record = fileScan.GetNextRec()) != null; i++){
			byte data[] = new byte[Constant.MAXNAME];
			System.arraycopy(record.data, 0, data, 0, Constant.MAXNAME);
			String username = new String(data);
			byte pass[] = new byte[Constant.MAXNAME];
			System.arraycopy(record.data, Constant.MAXNAME, pass, 0, Constant.MAXNAME);
			String pwd = new String(pass);
			
			if(u.toString().equals(username) && p.toString().equals(pwd)){
				byte b[] = new byte[4];
				System.arraycopy(record.data, Constant.MAXNAME*2, b, 0, Constant.INTSIZE);
				
				ID = Tuple.BytesToInt(b);
				byte db[] = new byte[Constant.MAXNAME];
				System.arraycopy(record.data, Constant.MAXNAME*2+Constant.INTSIZE, db, 0, Constant.MAXNAME);
	    		
				dir = new String();
				for(int k=0; k<Constant.MAXNAME; k++){
	    			if(db[k]!=0){
	    				char c[] = new char[1];
	    				c[0] = (char)db[k];
	    				dir+=(new String(c));
	    			}
	    			else
	    				break;
	    		}
			}
		}
		
		if(dir == null)
			return -1;
		else{
			sm = new SM_Manager();
			if(sm.OpenDb(dir) != RC.rc.SUCCESS){
				sm.CreateDB(dir);
				sm.OpenDb(dir);
			}
			
			openMap.put(ID, sm);
			return ID;
		}
	}
	
	public Operation queryExec(String cmdline, int userID){
		SM_Manager sm = openMap.get(userID);
		Parse p;
		
		try{
			p=new Parse(cmdline);
		}
		catch(Error e){
			throw e;
		}
		
		if(p.absyn instanceof CreateIndex){
			try{
				((CreateIndex)p.absyn).CrtIndex(sm);
			}
			catch(Error e){
				throw e;
			}
			
			Special_op op = new Special_op();
			
			String rel = ((CreateIndex)p.absyn).table;
			String s = ((CreateIndex)p.absyn).attr;
		    String attr = Tuple.Trim(s);
		    
			IndexItem index = new IndexItem(rel, attr);
			op.op = Special_op.PLUS;
			op.index = index;
			
			return op;
		}
		else
		if(p.absyn instanceof CreateTable){
			try{
				((CreateTable)p.absyn).CrtTable(sm);
			}
			catch(Error e){
				throw e;
			}
			
			Special_op op = new Special_op();
			op.op = Special_op.PLUS;
			op.rel = ((CreateTable)p.absyn).table_name.GetTableName();
			
			return op;
		}
		else
		if(p.absyn instanceof DropTable){
			try{
				((DropTable)p.absyn).DropRel(sm);
			}
			catch(Error e){
				throw e;
			}
			
			Special_op op = new Special_op();
			op.op = Special_op.MINUS;
			op.rel = ((DropTable)p.absyn).relname;
			
			return op;
		}
		if(p.absyn instanceof DeleteTuple){
			ExecuteEngine engine = new ExecuteEngine(sm);
			Operation query = null;
			try{
				query = engine.PQPlan(((DeleteTuple)p.absyn).CrtAgbPlan(sm));
			}
			catch(Error e){
				throw e;
			}
			
			query.Open();
			while(query.hasNext())
				query.GetNext();
			query.Close();
			
			return null;
		}
		else
		if(p.absyn instanceof Update){
			ExecuteEngine engine = new ExecuteEngine(sm);
			Operation query = null;
			try{
				query = engine.PQPlan(((Update)p.absyn).CrtAgbPlan(sm));
			}
			catch(Error e){
				throw e;
			}
			
			try{
				query.Open();
			}
			catch(Error e){
				throw e;
			}
			
			while(query.hasNext())
				query.GetNext();
			query.Close();
			
			return null;
		}
		else
		if(p.absyn instanceof Insert){
			try{
				((Insert)p.absyn).insertTuple(sm);
			}
			catch(Error e){
				throw e;
			}
			
			return null;
		}
		else
		if(p.absyn instanceof CreateView){
			try{
				((CreateView)p.absyn).CrtView(cmdline, sm);
			}
			catch(Error e){
				throw e;
			}
			
			Special_op op = new Special_op();
			op.op = Special_op.PLUS;
			op.view = ((CreateView)p.absyn).viewName;
			
			return op;
		}
		else
		if(p.absyn instanceof SFW){
			ExecuteEngine engine = new ExecuteEngine(sm);
			Operation query = null;
			try{
				query = engine.PQPlan(((SFW)p.absyn).CrtAgbPlan(sm));
			}
			catch(Error e){
				throw e;
			}
			
			return query;
		}
		return null;
	}
	
	public void unlog(int userID){
		SM_Manager sm = openMap.get(userID);
		sm.CloseDb();
		openMap.remove(userID);
	}
	
	public boolean register(String name, String password){
		RM_FileHandle filehandle = user_manager.OpenFile("userInfo");
		ScanType st = new ScanType(ScanType.TYPE_STRING, 
                Constant.MAXNAME, 0, ScanType.OP_NO,
                null, ScanType.PIN_NORMAL);

		RM_FileScan fileScan = new RM_FileScan(filehandle,st);
		RM_Record record;
		StringBuffer s = new StringBuffer(name);
		s.setLength(Constant.MAXNAME);
		
		int i=0;
		for(i=0; (record = fileScan.GetNextRec()) != null; i++){
			byte data[] = new byte[Constant.MAXNAME];
			System.arraycopy(record.data, 0, data, 0, Constant.MAXNAME);
			String username = new String(data);
			
			if(s.toString().equals(username))
				return false;
		}
		int ID = i+1;
		
		DataItem tuple[] = new DataItem[4];
		tuple[0] = new VarcharItem(s);
		s = new StringBuffer(password);
		s.setLength(Constant.MAXNAME);
		tuple[1] = new VarcharItem(s);
		tuple[2] = new IntegerItem(ID);
		s = new StringBuffer("DB"+ID);
		s.setLength(Constant.MAXNAME);
		tuple[3] = new VarcharItem(s);
		filehandle.InsertRec(Tuple.tupleToByte(tuple));
		user_manager.rm.CloseFile(filehandle);
		
		return true;
	}
	
	public List<String> getTables(int userID){
		SM_Manager sm = openMap.get(userID);
		List<String> tables = new ArrayList<String>();
		
		ScanType st = new ScanType(ScanType.TYPE_STRING, 
                Constant.MAXNAME, 0, ScanType.OP_NO,
                null, ScanType.PIN_NORMAL);

        RM_FileScan fileScan = new RM_FileScan(sm.relcatHandle, st);
        RM_Record record = null;
        
        while((record = fileScan.GetNextRec()) != null){
        	byte data[] = new byte[Constant.MAXNAME];
        	System.arraycopy(record.data, 0, data, 0, Constant.MAXNAME);
        	
			String s = new String(data);
		    String rel = Tuple.Trim(s);
		    
		    if(!rel.equals("relcat") && !rel.equals("attrcat") && 
		       !rel.equals("keycat") && !rel.equals("foreignkeycat") && 
		       !rel.equals("indexcat") && !rel.equals("viewcat"))
		    	tables.add(rel);
        }
        
		return tables;
	}
	
	public List<String> getViews(int userID){
		SM_Manager sm = openMap.get(userID);
		List<String> views = new ArrayList<String>();
		
		ScanType st = new ScanType(ScanType.TYPE_STRING, 
                Constant.MAXNAME, 0, ScanType.OP_NO,
                null, ScanType.PIN_NORMAL);

        RM_FileScan fileScan = new RM_FileScan(sm.viewcatHandle,st);
        RM_Record record;
        
        while((record = fileScan.GetNextRec())!=null){
        	byte data[] = new byte[Constant.MAXNAME];
        	System.arraycopy(record.data, 0, data, 0, Constant.MAXNAME);
        	views.add(new String(data));
        }
        fileScan.CloseScan();
        
		return views;
	}
	
	public List<IndexItem> getIndexes(int userID){
		SM_Manager sm = openMap.get(userID);
		List<IndexItem> indexes = new ArrayList<IndexItem>();
		
		ScanType st = new ScanType(ScanType.TYPE_STRING, 
                Constant.MAXNAME, 0, ScanType.OP_NO,
                null, ScanType.PIN_NORMAL);

        RM_FileScan fileScan = new RM_FileScan(sm.indexHandle, st);
        RM_Record record = null;
        
        while((record = fileScan.GetNextRec()) != null){
        	byte data[] = new byte[Constant.MAXNAME];
        	System.arraycopy(record.data, 0, data, 0, Constant.MAXNAME);
        	
			String s = new String(data);
		    String rel = Tuple.Trim(s);
		    
		    data = new byte[Constant.MAXNAME];
        	System.arraycopy(record.data, Constant.MAXNAME, data, 0, Constant.MAXNAME);
        	
			s = new String(data);
		    String attr = Tuple.Trim(s);
		    
		    indexes.add(new IndexItem(rel, attr));
        }
        
		return indexes;
	}
	
	public List<String> GetTitles(int userID, String tableName){
		SM_Manager sm = openMap.get(userID);
		List<String> titles = new ArrayList<String>();
		List<DataAttrInfo> info = new ArrayList<DataAttrInfo>();
		
		sm.GetDataAttrInfo(tableName, info);
		
		for(int i=0; i<info.size(); i++){
			String attr = info.get(i).attrName;
			String result = Tuple.Trim(attr);
		    titles.add(result);
		}
		
		return titles;
	}
}
